﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MbUnit.Framework;
using FlowBasis.Data;

namespace FlowBasisUnitTests.Data
{
    public class LinqExpressionHelperTests
    {
        [Test]
        public void Test_TryGetReferencedPropertyName()
        {
            string propertyName = LinqExpressionHelper.TryGetReferencedPropertyName<TestObject>(o => o.Id);
            Assert.AreEqual("Id", propertyName);

            propertyName = LinqExpressionHelper.TryGetReferencedPropertyName<TestObject>(null);
            Assert.IsNull(propertyName);

            // Another expression that is not a property reference.
            propertyName = LinqExpressionHelper.TryGetReferencedPropertyName<TestObject>(o => o.Id + o.Value);
            Assert.IsNull(propertyName);
        }


        [Test]
        public void Test_CreatePropertyMatchExpression()
        {
            var testSet = new[]
            {
                new TestObject { Id = 2, Name = "Number2", Value = 24 },
                new TestObject { Id = 7, Name = "Number7", Value = 12 },
                new TestObject { Id = 40, Name = "Number40", Value = 24 }
            }
            .AsQueryable();
            
            var matchExpression = LinqExpressionHelper.CreatePropertyMatchLambdaExpression<TestObject>("Id", 7);

            TestObject result = testSet.Single(matchExpression);
            Assert.AreEqual("Number7", result.Name);
            
            matchExpression = LinqExpressionHelper.CreatePropertyMatchLambdaExpression<TestObject>("Id", 40);

            result = testSet.Single(matchExpression);
            Assert.AreEqual("Number40", result.Name);
        }


        [Test]
        public void Test_CreatePropertyMatchExpression_With_Nullable_Property()
        {
            var testSet = new[]
            {
                new TestObject { Id = 2, Name = "Number2", NullableInt = 12 },
                new TestObject { Id = 7, Name = "Number7", NullableInt = null },
                new TestObject { Id = 40, Name = "Number40", NullableInt = 24 }
            }
            .AsQueryable();

            // Try with parameter expression created internally.
            var matchExpression = LinqExpressionHelper.CreatePropertyMatchLambdaExpression<TestObject>("NullableInt", 24);

            var result = testSet.Single(matchExpression);
            Assert.AreEqual("Number40", result.Name);

            // Try to get the null value.
            matchExpression = LinqExpressionHelper.CreatePropertyMatchLambdaExpression<TestObject>("NullableInt", null);

            result = testSet.Single(matchExpression);
            Assert.AreEqual("Number7", result.Name);
        }


        [Test]
        public void Test_CreateMultiplePropertyMatchExpression()
        {
            var testSet = new[]
            {
                new TestObject { Id = 2, Name = "Number2", Value = 24 },
                new TestObject { Id = 7, Name = "Number7", Value = 12 },
                new TestObject { Id = 40, Name = "Number40", Value = 24 }
            }
            .AsQueryable();

            var matchExpression = LinqExpressionHelper.CreateMultiplePropertyMatchLambdaExpression<TestObject>(
                new [] { "Value", "Id" },
                new object[] { 24, 40 });

            TestObject result = testSet.Single(matchExpression);
            Assert.AreEqual("Number40", result.Name);
        }


        [Test]
        public void Test_CreatePropertyInListExpression()
        {
            var testSet = new[]
            {
                new TestObject { Id = 2, Name = "Number2", Value = 24 },
                new TestObject { Id = 7, Name = "Number7", Value = 12 },
                new TestObject { Id = 40, Name = "Number40", Value = 24 }
            }
            .AsQueryable();

            var matchExpression = LinqExpressionHelper.CreatePropertyInListLamdaExpression<TestObject>(                
                "Id", new List<int> { 2, 40, -1000 });

            List<TestObject> results = testSet.Where(matchExpression).OrderBy(o => o.Id).ToList();
            Assert.AreEqual(2, results.Count);
            Assert.AreEqual(2, results[0].Id);
            Assert.AreEqual(40, results[1].Id);
            
            matchExpression = LinqExpressionHelper.CreatePropertyInListLamdaExpression<TestObject>(
                "Name", new List<string> { "Number7", "Not there", "Number40" });

            results = testSet.Where(matchExpression).OrderBy(o => o.Id).ToList();
            Assert.AreEqual(2, results.Count);
            Assert.AreEqual(7, results[0].Id);
            Assert.AreEqual(40, results[1].Id);
        }


        public class TestObject
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Value { get; set; }

            public int? NullableInt { get; set; }
        }
    }

}
